package osvscanner

import (
	"testing"

	"github.com/google/osv-scalibr/extractor"
	"github.com/google/osv-scalibr/extractor/filesystem/language/javascript/packagelockjson"
	"github.com/google/osv-scalibr/purl"
	"github.com/google/osv-scanner/v2/internal/config"
	"github.com/google/osv-scanner/v2/internal/imodels"
	"github.com/google/osv-scanner/v2/internal/imodels/results"
	"github.com/google/osv-scanner/v2/internal/testutility"
	"github.com/google/osv-scanner/v2/pkg/models"
	"github.com/ossf/osv-schema/bindings/go/osvschema"
)

func Test_assembleResult(t *testing.T) {
	t.Parallel()
	type args struct {
		actions     ScannerActions
		scanResults *results.ScanResults
		config      config.Manager
	}
	packages := []imodels.PackageInfo{
		{
			Package: &extractor.Package{
				Name:      "pkg-1",
				PURLType:  purl.TypeNPM,
				Plugins:   []string{packagelockjson.Name},
				Version:   "1.0.0",
				Locations: []string{"dir/package-lock.json"},
			},
		},
		{
			Package: &extractor.Package{
				Name:      "pkg-2",
				PURLType:  purl.TypeNPM,
				Plugins:   []string{packagelockjson.Name},
				Version:   "1.0.0",
				Locations: []string{"dir/package-lock.json"},
			},
		}, {
			Package: &extractor.Package{
				Name:      "pkg-3",
				PURLType:  purl.TypeNPM,
				Plugins:   []string{packagelockjson.Name},
				Version:   "1.0.0",
				Locations: []string{"other-dir/package-lock.json"},
			},
		},
	}
	vulnsResp := [][]*osvschema.Vulnerability{
		{
			{
				Id:      "GHSA-123",
				Aliases: []string{"CVE-123"},
			},
			{
				Id: "CVE-123",
			},
		},
		{},
		{
			{
				Id: "GHSA-456",
			},
		},
	}

	licensesResp := [][]models.License{
		{models.License("MIT"), models.License("0BSD")},
		{models.License("MIT")},
		{models.License("UNKNOWN")},
	}

	makeLicensesResp := func() [][]models.License {
		cpy := make([][]models.License, len(licensesResp))
		copy(cpy, licensesResp)

		return cpy
	}

	// makeScanResults make a separate instance of ScanResults to avoid mutations changing other tests
	makeScanResults := func() *results.ScanResults {
		scanResults := results.ScanResults{
			ConfigManager: config.Manager{},
		}
		licensesResp = makeLicensesResp()
		for i := range packages {
			scanResults.PackageScanResults = append(scanResults.PackageScanResults, imodels.PackageScanResult{
				PackageInfo:     packages[i],
				Vulnerabilities: vulnsResp[i],
				Licenses:        licensesResp[i],
			})
		}

		return &scanResults
	}

	callAnalysisStates := make(map[string]bool)

	tests := []struct {
		name string
		args args
	}{
		{
			name: "group_vulnerabilities",
			args: args{
				scanResults: makeScanResults(),
				actions: ScannerActions{
					ShowAllPackages:       false,
					ScanLicensesAllowlist: nil,
					CallAnalysisStates:    callAnalysisStates,
				},
			},
		},
		{
			name: "group_vulnerabilities_with_all_packages_included",
			args: args{
				scanResults: makeScanResults(),
				actions: ScannerActions{
					ShowAllPackages:       true,
					ScanLicensesAllowlist: nil,
					CallAnalysisStates:    callAnalysisStates,
				},
			},
		}, {
			name: "group_vulnerabilities_with_licenses",
			args: args{
				scanResults: makeScanResults(),
				actions: ScannerActions{
					ShowAllPackages:       true,
					ScanLicensesSummary:   true,
					ScanLicensesAllowlist: nil,
					CallAnalysisStates:    callAnalysisStates,
				},
			},
		}, {
			name: "group_vulnerabilities_with_license_allowlist",
			args: args{
				scanResults: makeScanResults(),

				actions: ScannerActions{
					ShowAllPackages:       false,
					ScanLicensesAllowlist: []string{"MIT", "0BSD"},
					CallAnalysisStates:    callAnalysisStates,
				},
			},
		}, {
			name: "group_vulnerabilities_with_license_allowlist_and_license_override",
			args: args{
				scanResults: makeScanResults(),
				actions: ScannerActions{
					ShowAllPackages:       false,
					ScanLicensesAllowlist: []string{"MIT", "0BSD"},
					CallAnalysisStates:    callAnalysisStates,
				},
				config: config.Manager{
					OverrideConfig: &config.Config{
						PackageOverrides: []config.PackageOverrideEntry{
							{
								Name:      "pkg-3",
								Ecosystem: "npm",
								License: config.License{
									Override: []string{"MIT"},
								},
							},
						},
					},
				},
			},
		}, {
			name: "group_vulnerabilities_with_license_allowlist_and_all_packages",
			args: args{
				scanResults: makeScanResults(),
				actions: ScannerActions{
					ShowAllPackages:       true,
					ScanLicensesAllowlist: []string{"MIT", "0BSD"},
					CallAnalysisStates:    callAnalysisStates,
				},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			t.Parallel()
			tt.args.scanResults.ConfigManager = tt.args.config
			got := buildVulnerabilityResults(tt.args.actions, tt.args.scanResults)
			testutility.NewSnapshot().MatchJSON(t, got)
		})
	}
}
